Skip to content

Fix: Log unhandled exceptions in Node.js #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 14, 2015
Merged

Fix: Log unhandled exceptions in Node.js #30

merged 9 commits into from
Oct 14, 2015

Conversation

frankebersoll
Copy link
Contributor

This is the first pull request for issue #29.

It adds an IExitController which is responsible for behavior when the application is exiting. If isApplicationExiting is true, NodeSubmissionClient will use synchronous event submission. A child process will be spawned synchronously, and pipes are used to transmit the request and response data.

Try it out using the following test:

var client = require("./dist/exceptionless.node.js").ExceptionlessClient.default;
var spawnSync = require("child_process").spawnSync;
var events = require("events");

client.config.apiKey = "WHATEVER";
client.config.useDebugLogger();

throw new Error("Test: Error");

if (message !== null) {
client.submitLog(BEFORE_EXIT, message, 'Error')
client.submitLog(EXIT, message, 'Error')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above says only sync code can run but this will trigger a pipeline to run (various chained plugins) which will also enqueue the event). Does this work okay?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see, all plugins run synchronously (the run-signature gets a context object and no callback). If we ever run code here that depends on callbacks, this code would have to know the isApplicationExiting-state and run synchronously.

But as long as submitEvent(E); queue.process(); work, this should work too.

@ejsmith
Copy link
Member

ejsmith commented Oct 8, 2015

Thanks for the contribution!

@niemyjski
Copy link
Member

Thank you very much for the pull request! Awesome job man! I know it was a lot of hard work. I don't follow one part of of the child process workflow and was wondering if we could meet up and you could give me a quick tour. I'd just like to follow 100% how it works so I can help support it and help maintain it :).

I was also wondering about your exit controller and wanted your feedback ( @frankebersoll @ejsmith). I was wondering if there is ever a time we would want more behaviors:

  • On Exit
  • On Freeze (when the tab isn't active).

I'm not sure if we'd need these or not. If you can think of any other behaviors we might need to support we might want to refactor the exit controller into a behavior that covers on exit. Do you think we would ever need this, and if so do you think we should future proof it??

@frankebersoll frankebersoll deleted the master branch October 9, 2015 08:52
@frankebersoll frankebersoll restored the master branch October 9, 2015 08:54
@frankebersoll
Copy link
Contributor Author

Okay, now I know what "rename branch" in Tower actually does... 😔

@frankebersoll frankebersoll reopened this Oct 9, 2015
@frankebersoll
Copy link
Contributor Author

Okay, now we have:

  • TypeScript 1.6.2
  • Up-to-date node.d.ts
  • Unmodified console output of unhandled exceptions
  • Submission on Ctrl+C

port: parsedHost.port && parseInt(parsedHost.port),
path: path
};
private sendRequestSync(request: NodeSubmissionRequest, callback: NodeSubmissionCallback): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not an expert with Node. Guessing this is the only way to do a synchronous http request?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Node.js, there is only a single thread. As long as there are any open pending callbacks (either timers or I/O), the application will continue. As soon as all callbacks in the queue are processed, the application exits.

There are exceptions to this rule: In case of an uncaught exception or a call to process.exit(), no other handlers are processed. Instead, the process.on("exit") handlers run, but immediately after the application will exit.

The http API in Node.js is completely asynchronous, meaning that requests are sent using a callback to wait for the response. As we can't wait for callbacks inside process.on("exit") we have to use a child process, as spawnSync actually allows us to wait for the child process to finish.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Nice hack. :-)

expect(response.message).toBe('Unable to connect to server.');
}
var description = {
email_address: '[email protected]',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noticed a typo with noreply

@niemyjski
Copy link
Member

Ship it

frankebersoll added a commit that referenced this pull request Oct 14, 2015
Fix: Log unhandled exceptions in Node.js
@frankebersoll frankebersoll merged commit 363004f into exceptionless:master Oct 14, 2015
@frankebersoll frankebersoll deleted the master branch October 15, 2015 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants